using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Globalization;

using D = System.Drawing;
using System.IO;
using System.Resources;
using MosziNET.Web.Gallery.Properties;

namespace MosziNET.Web.Gallery.Handlers
{
    /// <summary>
    /// Handles the thumbnail requests
    /// </summary>
    public class ImageHandler : HandlerBase<ImageHandler.ThumbnailParams>
    {
        #region / Request parameters class /

        /// <summary>
        /// Holds the parameters of this request
        /// </summary>
        public class ThumbnailParams
        {
            public string fid = String.Empty;
            public string fn = String.Empty;
            public string f = String.Empty;
            public string t = String.Empty;

            /// <summary>
            /// The id of the folder
            /// </summary>
            public string FolderId
            {
                get
                {
                    return this.fid;
                }
            }

            /// <summary>
            /// The file to show
            /// </summary>
            public string ImageName
            {
                get
                {
                    return this.fn;
                }
            }

            /// <summary>
            /// Are we showing a thumb for a folder ?
            /// </summary>
            public bool IsFolder
            {
                get
                {
                    return this.f == "1";
                }
            }

            public bool IsThumbnail
            {
                get
                {
                    return this.t == "1";
                }
            }
        }

        #endregion / Request parameters class /

        #region / Private fields /

        private const int thumbMaxSize = 94;
        private const int thumbFolderSize = 25;
        private const int bufferSize = 40 * 1024;

        #endregion / Private fields /

        #region / IHttpHandler Members /

        /// <summary>
        /// Defines if this handler is reusable or not
        /// </summary>
        public override bool IsReusable
        {
            get { return true; }
        }

        /// <summary>
        /// Processes the request
        /// </summary>
        /// <param name="context"></param>
        public override void ProcessRequest(HttpContext context)
        {
            base.ProcessRequest(context);

            context.Response.ContentType = "image/jpeg";

            // build a folder image object
            FolderImage folderImage = new FolderImage();
            folderImage.ParentFolder = this.RequestParameters.FolderId;
            folderImage.ImageName = this.RequestParameters.ImageName;

            if (this.RequestParameters.IsThumbnail)
            {
                // get the thumbnail
                byte[] thumbContent = GetThumbnail(context, folderImage,
                    this.RequestParameters.IsFolder);
                if (thumbContent == null)
                {
                    Resources.Inf.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
                else
                {
                    // finally write out the thumbnail
                    context.Response.OutputStream.Write(thumbContent, 0, thumbContent.Length);
                }
            }
            else
            {
                // get the image and output to the response stream
                using (Stream fileContent = GalleryManager.StorageProvider.GetImage(folderImage))
                {
                    if (fileContent != null)
                    {
                        byte[] buffer = new byte[bufferSize];
                        int readCount = 0;
                        while ((readCount = fileContent.Read(buffer, 0, bufferSize)) > 0)
                        {
                            context.Response.OutputStream.Write(buffer, 0, readCount);
                        }
                    }
                }
            }
        }

        #endregion / IHttpHandler Members /

        #region / Helper methods /

        /// <summary>
        /// Returns the cached or generated thumbnail content
        /// </summary>
        /// <param name="context"></param>
        /// <param name="thumbnail"></param>
        /// <param name="isFolderThumbnail"></param>
        /// <returns></returns>
        public byte[] GetThumbnail(HttpContext context, FolderImage thumbnail, bool isFolderThumbnail)
        {
            string thubmnailId = GetCachedFileName(thumbnail, isFolderThumbnail);

            byte[] thumbnailContent = null;

            // first if the cached is turned on, then try to get the thumb for the cache
            if (GalleryManager.CacheThumbnails)
            {
                // try the storage cache
                thumbnailContent = GalleryManager.StorageProvider.GetCachedThumbnail(thubmnailId);
            }

            // if the cache retrievals was not successful, then generate the thumb
            if (thumbnailContent == null)
            {
                using (Stream bigImage = GalleryManager.StorageProvider.GetImage(thumbnail))
                {
                    if (bigImage == null)
                        return null;

                    using (D.Image thumbImage = GenerateThumbnail(bigImage, context))
                    {
                        using (MemoryStream ms = new MemoryStream())
                        {
                            thumbImage.Save(ms, D.Imaging.ImageFormat.Jpeg);
                            thumbnailContent = ms.ToArray();
                        }

                        // if cache is turned on then cache the thumbnail
                        if (GalleryManager.CacheThumbnails)
                        {
                            GalleryManager.StorageProvider.CacheThumbnail(thubmnailId, thumbnailContent);
                        }
                    }
                }
            }

            return thumbnailContent;
        }

        /// <summary>
        /// Builds a unique file name on the thumbnail
        /// </summary>
        /// <param name="thumbnail"></param>
        /// <param name="isFolderThumbnail"></param>
        /// <returns></returns>
        private string GetCachedFileName(FolderImage thumbnail, bool isFolderThumbnail)
        {
            return String.Format(CultureInfo.InvariantCulture, "{0}_{1}_{2}",
                isFolderThumbnail ? "1" : "0", thumbnail.ParentFolder, thumbnail.ImageName);
        }

        #endregion / Helper methods /

        #region / Image processing methods /

        private D.Image GenerateThumbnail(Stream content, HttpContext context)
        {
            // open the image
            using (D.Image bigImage = D.Image.FromStream(content))
            {
                // convert it to the required size
                double ratio = (double)bigImage.Width / (double)bigImage.Height;
                int width, height;

                if (ratio > 1)
                    ratio = 1 / ratio;

                if (bigImage.Width > bigImage.Height)
                {
                    width = thumbMaxSize;
                    height = Convert.ToInt32(thumbMaxSize * ratio);
                }
                else
                {
                    width = Convert.ToInt32(thumbMaxSize * ratio);
                    height = thumbMaxSize;
                }

                D.Image background;

                // generate the thumbnail image
                using (D.Image thumbImage = bigImage.GetThumbnailImage(width, height,
                    new D.Image.GetThumbnailImageAbort(ThumbnailAbort),
                    IntPtr.Zero))
                {

                    background = new D.Bitmap(thumbMaxSize, thumbMaxSize);
                    using (D.Graphics g = D.Graphics.FromImage(background))
                    {
                        g.FillRectangle(
                            new D.SolidBrush(D.Color.FromArgb(20, 20, 20)),
                            0, 0, thumbMaxSize, thumbMaxSize);
                        int left = (thumbMaxSize - width) / 2;
                        int top = (thumbMaxSize - height) / 2;

                        g.DrawImage(thumbImage, left, top, width, height);
                    }
                }

                // do some post processing if required
                PostProcessThumb(background, this.RequestParameters.IsFolder);

                // return the image
                return background;
            }
        }

        /// <summary>
        /// Post processes the thumbnail
        /// </summary>
        /// <param name="thumbnail"></param>
        /// <param name="isFolder"></param>
        private void PostProcessThumb(D.Image thumbnail, bool isFolder)
        {
            if (isFolder)
            {
                using (D.Graphics g = D.Graphics.FromImage(thumbnail))
                {
                    g.DrawImage(Properties.Resources.FolderImage,
                        thumbnail.Width - thumbFolderSize - 3,
                        thumbnail.Height - thumbFolderSize - 3, thumbFolderSize, thumbFolderSize);
                }
            }
        }

        /// <summary>
        /// The deleagte needed for the htt
        /// </summary>
        /// <returns></returns>
        private bool ThumbnailAbort()
        {
            return false;
        }

        #endregion / Image processing methods /
    }
}
